package com.jiangyao.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jiangyao.common.constants.ConfigConstants;
import com.jiangyao.common.handler.GlobalExceptionHandler;
import com.jiangyao.service.ConfigService;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

public class WechatUtils {

	private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

	//公众号相关
//	private static final String APP_ID = "";
//	private static final String APP_SECRET = "";
	public static final String OPENID_NAME = "";

	private static final String ACCESS_TOKEN = "ACCESS_TOKEN";
	private static final String JS_TICKET = "JS_TICKET";
	private static Map<String, String> syncMap = new Hashtable<>();
	private static long refreshTime = 0L;

	private static ConfigService configService;

	static {

		if (configService == null) {
			configService = SpringBeanFactoryUtils.getBean(ConfigService.class);
		}
//		refreshAccessToken();
//		refreshJs_ticket();

	}


	/**
	 * 定时刷新 token
	 * token 有效期为2小时，所以至少每2小时刷新
	 */
//	@Scheduled(cron = "0 0 0/1 * * ? ")
	public static void refreshTokens() {
		refreshAccessToken();
		refreshJs_ticket();
	}


	/**
	 * 刷新微信微信公众号 AccessToken
	 *
	 * @return AccessToken
	 */
	public static String refreshAccessToken() {
		try {
			String url = "https://api.weixin.qq.com/cgi-bin/token";
			Map<String, Object> params = new HashMap<>();
			params.put("grant_type", "client_credential");
			params.put("appid", configService.getValueFromCache(ConfigConstants.WECHAT_APP_ID));
			params.put("secret", configService.getValueFromCache(ConfigConstants.WECHAT_APP_SECRET));
			final String result = HttpClientUtil.httpGetRequest(appendGetParams(url, params));
			JSONObject resultJson = JSONObject.parseObject(result);
			String access_token = resultJson.getString("access_token");
			syncMap.put(ACCESS_TOKEN, access_token);
			return access_token;
		} catch (Exception e) {
			LOGGER.error("刷新微信微信公众号 AccessToken 异常：{}", e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 刷新微信微信公众号 Js_ticket
	 *
	 * @return Js_ticket
	 */
	public static String refreshJs_ticket() {
		try {
			String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
			Map<String, Object> params = new HashMap<>();
			params.put("access_token", syncMap.get(ACCESS_TOKEN));
			params.put("type", "jsapi");
			String result = HttpClientUtil.httpGetRequest(appendGetParams(url, params));
			JSONObject resultJson = JSONObject.parseObject(result);
			int errorcode = resultJson.getInteger("errcode");
			if (errorcode != 0 && refreshTime < System.currentTimeMillis() - 600000L) {
				refreshAccessToken();
				params.put("access_token", syncMap.get(ACCESS_TOKEN));
				result = HttpClientUtil.httpGetRequest(appendGetParams(url, params));
				resultJson = JSONObject.parseObject(result);
			}
			String js_ticket = resultJson.getString("ticket");
			syncMap.put(JS_TICKET, js_ticket);
			return js_ticket;
		} catch (Exception e) {
			LOGGER.error("刷新微信微信公众号 Js_ticket 异常：{}", e.getMessage(), e);
		}
		return "";
	}

	public static Map<String, String> generateWechatJsParams(String url) {
		synchronized (syncMap) {
			Map<String, String> ret = new HashMap<>();
			if (StringUtils.isEmpty(url)) {
				return ret;
			}

			try {
				url = URLDecoder.decode(url, "utf-8");
			} catch (Exception e) {
				LOGGER.error(e.getMessage(), e);
			}
			if (url.contains("#")) {
				url = url.split("#")[0];
			}
			String nonce_str = create_nonce_str();
			String timestamp = create_timestamp();
			String string1;
			String signature = "";

			// 注意这里参数名必须全部小写，且必须有序
			final String js_ticket = syncMap.get(JS_TICKET);
			string1 = "jsapi_ticket=" + js_ticket + "&noncestr=" + nonce_str
					+ "&timestamp=" + timestamp + "&url=" + url;
			LOGGER.info(string1);

			try {
				MessageDigest crypt = MessageDigest.getInstance("SHA-1");
				crypt.reset();
				crypt.update(string1.getBytes("UTF-8"));
				signature = byteToHex(crypt.digest());
			} catch (Exception e) {
				e.printStackTrace();
			}
			ret.put("url", url);
			ret.put("appId", configService.getValueFromCache(ConfigConstants.WECHAT_APP_ID));
			ret.put("jsapi_ticket", js_ticket);
			ret.put("nonceStr", nonce_str);
			ret.put("timestamp", timestamp);
			ret.put("signature", signature);
			LOGGER.info(signature);
			return ret;
		}
	}

	private static String byteToHex(final byte[] hash) {
		Formatter formatter = new Formatter();
		for (byte b : hash) {
			formatter.format("%02x", b);
		}
		String result = formatter.toString();
		formatter.close();
		return result;
	}

	private static String create_nonce_str() {
		return StringUtils.getRandomString(16);
//		return UUID.randomUUID().toString();

	}

	private static String create_timestamp() {
		return Long.toString(System.currentTimeMillis() / 1000);
	}

	public static String encodingURL(String res)
			throws UnsupportedEncodingException {
		return URLEncoder.encode(res, "UTF-8");
	}

	public static String getUserAuthURL(boolean isBase, String returnURL,
	                                    String state) throws UnsupportedEncodingException {
		String url = "https://open.weixin.qq.com/connect/oauth2/authorize";
		Map<String, Object> params = new LinkedHashMap<>();
		params.put("appid", configService.getValueFromCache(ConfigConstants.WECHAT_APP_ID));
		params.put("redirect_uri", encodingURL(returnURL));
		params.put("response_type", "code");
		params.put("scope", isBase ? "snsapi_base" : "snsapi_userinfo");
		params.put("state", StringUtils.isEmpty(state) ? "0" : state);
		final String authURL = appendGetParams(url, params) + "#wechat_redirect";
		LOGGER.info(authURL);
		return authURL;
	}

	/**
	 * 通过授权code获取openID
	 *
	 * @param code code
	 * @return openid
	 * @ 异常
	 */
	public static String getUserOpenId(String code) {
		String url = "https://api.weixin.qq.com/sns/oauth2/access_token";
		Map<String, Object> params = new HashMap<>();
		params.put("appid", configService.getValueFromCache(ConfigConstants.WECHAT_APP_ID));
		params.put("secret", configService.getValueFromCache(ConfigConstants.WECHAT_APP_SECRET));
		params.put("code", code);
		params.put("grant_type", "authorization_code");
		return HttpClientUtil.httpGetRequest(appendGetParams(url, params));
	}

	public static String getUserNoticeInfo(String openId) {
		String url = "https://api.weixin.qq.com/cgi-bin/user/info";
		Map<String, Object> params = new LinkedHashMap<>();
		params.put("access_token", syncMap.get(ACCESS_TOKEN));
		params.put("openid", openId);
		params.put("lang", "zh_CN");
		return HttpClientUtil.httpGetRequest(appendGetParams(url, params));
	}

	public static String getUserDetailInfo(String userId, String access_token) {
		String url = "https://api.weixin.qq.com/sns/userinfo";
		Map<String, Object> params = new HashMap<>();
		params.put("access_token", access_token);
		params.put("openid", userId);
		params.put("lang", "zh_CN");
		return HttpClientUtil.httpGetRequest(appendGetParams(url, params));
	}


	public static String getContentCharSet(final HttpEntity entity) {
		if (entity == null) {
			throw new IllegalArgumentException("HTTP entity may not be null");
		}
		String charset = null;
		if (entity.getContentType() != null) {
			HeaderElement values[] = entity.getContentType().getElements();
			if (values.length > 0) {
				NameValuePair param = values[0].getParameterByName("charset");
				if (param != null) {
					charset = param.getValue();
				}
			}
		}
		if (StringUtils.isEmpty(charset)) {
			charset = "UTF-8";
		}
		return charset;
	}

	private static String appendGetParams(String url, Map<String, Object> params) {
		StringBuffer urlSB = new StringBuffer(url);
		if (params == null || params.isEmpty()) {
			return urlSB.toString();
		}
		if (url.contains("?")) {
			urlSB.append("&");
		} else {
			urlSB.append("?");
		}
		for (Entry<String, Object> param : params.entrySet()) {
			urlSB.append(param.getKey());
			urlSB.append("=");
			urlSB.append(param.getValue());
			urlSB.append("&");
		}
		urlSB.deleteCharAt(urlSB.length() - 1);
		return urlSB.toString();
	}


	// ***********************************************会用到的功能
	// ***********************************************//

	/**
	 * 给指定微信用户发送带链接的图文消息
	 *
	 * @param openId
	 * @param title
	 * @param msg
	 * @param picURL
	 * @param linkURL
	 * @return
	 * @throws Exception
	 */
	public static String sendNewsMsgToUser(String openId, String title,
	                                       String msg, String picURL, String linkURL) throws Exception {
		String sendMsgAPIurl = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="
				+ syncMap.get(ACCESS_TOKEN);
		Map<String, Object> params = new LinkedHashMap<>();
		params.put("touser", openId);
		params.put("msgtype", "news");
		Map<String, Object> articles = new LinkedHashMap<>();
		Map<String, String> news = new LinkedHashMap<>();
		news.put("title", title);
		news.put("description", msg);
		news.put("url", linkURL);
		news.put("picurl", picURL);
		articles.put("articles", new Map[]{news});
		params.put("news", articles);
		return HttpClientUtil.httpPostRequest(sendMsgAPIurl, params);
	}

	/**
	 * 给指定微信用户发送纯文本消息
	 *
	 * @param openId
	 * @param msg
	 * @return
	 * @throws Exception
	 */
	public static String sendTextMsgToUser(String openId, String msg) {
		String sendMsgAPIurl = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="
				+ syncMap.get(ACCESS_TOKEN);
		Map<String, Object> params = new LinkedHashMap<>();
		params.put("touser", openId);
		params.put("msgtype", "text");
		Map<String, String> text = new LinkedHashMap<>();
		text.put("content", msg);
		params.put("text", text);
		return HttpClientUtil.httpPostRequest(sendMsgAPIurl, params);
	}

	/**
	 * 判断用户是否关注（订阅）
	 *
	 * @param openId
	 * @return
	 * @throws Exception
	 */
	public static boolean checkSubscribe(String openId) throws Exception {
		if (StringUtils.isEmpty(openId)) {
			return false;
		}
		String userInfoStr = getUserNoticeInfo(openId);
		JSONObject userInfoJson = JSON.parseObject(userInfoStr);
		int subscribe = userInfoJson.getIntValue("subscribe");
		return subscribe == 1 ? true : false;
	}

	// 模板消息发送方法
	public static String test(String openId, String tutorNum, String userName, Date date) {
		String access_token = syncMap.get(ACCESS_TOKEN);
		String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="
				+ access_token;
		Map<String, Object> params = new LinkedHashMap<>();
		params.put("touser", openId);
//		params.put("template_id", "6is9TUTeD99xODX_PcEyhuuwFL7MvjZ7IxQlu_posw4");
		params.put("template_id", "yt0nKRKjfPjIkzR7Mfj2ADOUbbge4avSLseb3gh3Ums");
		//params.put("template_id","");
		Map<String, Object> articles = new LinkedHashMap<>();
		Map<String, String> news = new LinkedHashMap<>();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
		news.put("value", userName + "，您好！您的本次导师志愿服务已经结束。");
		news.put("color", "#173177");
		Map<String, String> news1 = new LinkedHashMap<>();
		news1.put("value", sdf.format(date));
		news1.put("color", "#173177");
		Map<String, String> news2 = new LinkedHashMap<>();
		news2.put("value", sdf.format(new Date()));
		news2.put("color", "#173177");
		Map<String, String> news3 = new LinkedHashMap<>();
		news3.put("value", tutorNum);
		news3.put("color", "#173177");
		Map<String, String> news4 = new LinkedHashMap<>();
		news4.put("value", userName);
		news4.put("color", "#173177");
		Map<String, String> news5 = new LinkedHashMap<>();
		news5.put("value", "扶持一个青年，成就未来一个企业家！");
		news5.put("color", "#173177");

		articles.put("first", news);
		articles.put("keyword1", news1);
		articles.put("keyword2", news2);
		articles.put("keyword3", news3);
		articles.put("keyword4", news4);
		articles.put("remark", news5);
		params.put("data", articles);
		try {
			String result = HttpClientUtil.httpPostRequest(url, params);
			return result;
		} catch (Exception e) {

		}
		return null;
	}

}
